package com.easylinkin.linkappapi.lobar.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.easylinkin.linkappapi.common.service.AppSendMessageService;
import com.easylinkin.linkappapi.lobar.constant.LobarConstant.WaringType;
import com.easylinkin.linkappapi.lobar.constant.LobarConstant.WarningMsgTemplate;
import com.easylinkin.linkappapi.lobar.constant.LobarConstant.WarningRule;
import com.easylinkin.linkappapi.lobar.dto.GroupDTO;
import com.easylinkin.linkappapi.lobar.dto.UserProjectDTO;
import com.easylinkin.linkappapi.lobar.entity.*;
import com.easylinkin.linkappapi.lobar.entity.emp.EmpUserBaseDTO;
import com.easylinkin.linkappapi.lobar.mapper.*;
import com.easylinkin.linkappapi.lobar.service.UserOutinWarningService;
import com.easylinkin.linkappapi.lobar.service.UserProjectService;
import com.easylinkin.linkappapi.tenant.entity.LinkappTenant;
import com.easylinkin.linkappapi.tenant.mapper.LinkappTenantMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import site.morn.rest.RestMessage;

import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: kan yuanfeng
 * @Date: 2022/5/25 15:41
 * @Description: 预警定时任务
 */
@Slf4j
@Component
@Configuration
@EnableScheduling
@ConditionalOnProperty(prefix = "scheduling.warning", name = "enabled", havingValue = "true")
public class WarningTimer {

    @Autowired
    private LinkappTenantMapper linkappTenantMapper;
    @Autowired
    private UserWarningMapper userWarningMapper;
    @Autowired
    private AgeWarningMapper ageWarningMapper;
    @Autowired
    private CertificateWarningMapper certificateWarningMapper;
    @Autowired
    private WarningConfigMapper warningConfigMapper;
    @Autowired
    private UserRecordMapper userRecordMapper;
    @Autowired
    private UserProjectMapper userProjectMapper;
    @Autowired
    private UserCertificateMapper userCertificateMapper;
    @Autowired
    private GroupMapper groupMapper;
    @Autowired
    private GroupWarningMapper groupWarningMapper;
    @Autowired
    private UserClockMapper userClockMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserProjectService userProjectService;
    @Autowired
    private UserOutinWarningService userOutinWarningService;
    @Autowired
    private AppSendMessageService appSendMessageService;

    private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(WarningTimer.class);

    //定义一个缓存key
    private String wKey = "wKey-";

    //@Scheduled(cron = "0 5 0 * * ?")
    //@Scheduled(cron = "0 5 0 * * ?")
    @Scheduled(cron = "${scheduling.warning.checkWarning.cron}")
    public void checkWarning() {
        try {
            LOGGER.info("------开始预警定时任务----------checkWarning------start-----");
            //查询所有项目
            List<LinkappTenant> list = linkappTenantMapper.selectByProjectId(null);
            list.removeIf(l -> "1".equals(l.getId()));
            //查询预警设置
            List<WarningConfig> configs = warningConfigMapper.selectList(new QueryWrapper<>());
            list.forEach(l -> {
                //取预警设置，没有就取默认
                WarningConfig warningConfig;
                List<WarningConfig> configList = configs.stream()
                        .filter(c -> l.getId().equals(c.getTenantId()))
                        .collect(Collectors.toList());
                if (configList.size() < 1) {
                    List<WarningConfig> collect = configs.stream()
                            .filter(c -> StringUtils.isBlank(c.getTenantId()))
                            .collect(Collectors.toList());
                    warningConfig = collect.get(0);
                } else {
                    warningConfig = configList.get(0);
                }
                //人员出勤预警
                userWaning(l.getId(), warningConfig);
                //年龄预警
                ageWaning(l.getId(), warningConfig);
                //证书预警
                certificateWarning(l.getId(), warningConfig);
                LOGGER.info("------完成预警定时任务----------checkWarning------end-----");
            });
        } catch (Exception e) {
            LOGGER.error("------预警定时任务异常----------checkWarning------error-----", e);
        }

    }

    /**
     * 班组考勤定时任务
     */
    @Scheduled(cron = "0 0/15 * * * ?")
    public void groupWarning() {
        try {
            LOGGER.info("------班组考勤定时任务----------groupWarning------start-----");
            //查询预警设置
            List<WarningConfig> configs = warningConfigMapper.selectList(new QueryWrapper<>());
            //查询所有的在场班组
            QueryWrapper<Group> groupQueryWrapper = new QueryWrapper<>();
            groupQueryWrapper.eq("status_", 1);
            List<Group> groupList = groupMapper.selectList(groupQueryWrapper);
            Map<String, List<Group>> map = groupList.stream()
                    .collect(Collectors.groupingBy(g -> g.getTenantId()));
            map.forEach((tenantId, groups) -> {
                //班组预警
                WarningConfig warningConfig = getWarningConfig(groups.get(0).getTenantId(), configs);

                //20220908增加判断预警设置开关
                Integer groupSwitch = warningConfig.getGroupSwitch();
                if (groupSwitch != null && groupSwitch.intValue() == 1) {
                    //预警检测时间
                    Date checkTime = this.getDate(warningConfig.getGroupCheck());
                    //时间到了才开始检测
                    if (System.currentTimeMillis() >= checkTime.getTime()) {
                        //如果进来过了tenantId放缓存(当天的开始时间作key，然后删除前一天的缓存)，以免下次再执；行
                        //删除前一天的缓存
                        delLastCache();
                        String key = DateUtil.beginOfDay(new Date()).getTime() + "";
                        List<String> list = (List<String>) redisTemplate.opsForValue().get(this.wKey + key);
                        if (null == list) {
                            list = new ArrayList<>();
                        }
                        if (!list.contains(tenantId)) {
                            groupWhandler(groups, warningConfig, checkTime);
                            list.add(tenantId);
                        }
                        redisTemplate.opsForValue().set(this.wKey + key, list);
                    }
                } else {
                    //删除前一天的缓存  这里是个容错处理，是担心redis里有过多的僵尸缓存
                    delLastCache();
                }

            });
            LOGGER.info("------班组考勤定时任务完成----------groupWarning------end-----");
        } catch (Exception e) {
            LOGGER.error("------班组考勤定时任务异常----------groupWarning------error-----");
        }
    }

    /**
     * 人员出场异常
     */
    @Scheduled(cron = "${scheduling.warning.userOutinWarning.cron}")
    public void userOutinWarning() {
        try {
            log.info("--人员出入场异常任务检测任务开始--");
            Date now = DateUtil.date();
            //周期是15分钟执行一次，设置一个周期内的阀值
            Date yzDate = DateUtil.offsetMinute(now, 15);
            String ymd = DateUtil.format(now, DatePattern.NORM_DATE_PATTERN);
            //查询预警设置
            QueryWrapper<WarningConfig> configQw = new QueryWrapper<>();
            configQw.isNotNull("tenant_id_");
            List<WarningConfig> configs = warningConfigMapper.selectList(configQw);
            if (CollectionUtil.isNotEmpty(configs)) {
                //一个租户应该只有一套配置，这里做下去重处理
                List<WarningConfig> finConfigs = configs.stream()
                        .collect(Collectors.collectingAndThen
                                (Collectors.toCollection(() ->
                                        new TreeSet<>(Comparator.comparing(WarningConfig::getTenantId))), ArrayList::new));

                finConfigs.stream().forEach(c -> {
                    //判断校验开关
                    Integer userOutSwitch = c.getUserOutSwitch();
                    if (userOutSwitch != null && userOutSwitch.intValue() == 1) {
                        //判断校验时间
                        String outCheck = c.getUserOutCheck();
                        String checkDateStr = ymd + " " + outCheck + ":00";
                        Date checkDate = DateUtil.parse(checkDateStr, DatePattern.NORM_DATETIME_PATTERN);
                        Date checkDateYz = DateUtil.offsetMinute(checkDate, 15);
                        //当前事件在检测时间之后，监测时间在延迟阈值时间前，当前时间在延迟监测时间阈值时间前
                        if (now.getTime() >= checkDate.getTime() && checkDate.before(yzDate) && now.before(checkDateYz)) {
                            //开线程处理不用等待上一个租户的处理完
                            ThreadUtil.execAsync(() -> {
                                exeUserOutinWarning(c, now);
                            }, true);
                        }
                    }
                });
            }
            log.info("--人员出入场异常任务检测任务结束--");
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    /**
     * 执行人员进出场告警生成
     *
     * @param conf 配置
     * @param now  告警时间
     */
    private void exeUserOutinWarning(WarningConfig conf, Date now) {
        //这个方法下沉到service上，方便后面扩展手动调用执行
        log.info("--进入:执行人员进出场告警生成--");
        RestMessage restMessage = userOutinWarningService.exeUserOutinWarning(conf, now);
    }


    /**
     * 删除前一天的缓存
     */
    private void delLastCache() {
        Calendar calendar = DateUtil.beginOfDay(Calendar.getInstance());
        calendar.add(Calendar.DATE, -1);
        calendar.getTime().getTime();
        redisTemplate.delete(this.wKey + calendar.getTime().getTime() + "");
    }

    /**
     * 班组预警处理
     */
    private void groupWhandler(List<Group> groups, WarningConfig warningConfig, Date checkTime) {
        groups.forEach(g -> {
            //查询班组总人数
            QueryWrapper<UserProject> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("group_id_", g.getId())
                    .eq("status_", 1);
            Integer sum = userProjectMapper.selectCount(queryWrapper);
            //查询按时打卡人数
            List<UserClock> userClocks = userClockMapper
                    .findOnUser(g, DateUtil.beginOfDay(new Date()), checkTime);
            Set<String> userIds = userClocks.stream().map(u -> u.getUserId())
                    .collect(Collectors.toSet());
            //判断出勤率
            float part = 0f;
            if (null == sum) {
                sum = 0;
            }
            if (CollectionUtil.isNotEmpty(userIds) && sum > 0) {
                part = ((float) userIds.size() / (float) sum) * 100;
            }
            if (part < warningConfig.getGroup() && sum > 0) {
                GroupWarning groupWarning = new GroupWarning();
                groupWarning.setAttendance(warningConfig.getGroup());
                groupWarning.setDetail(userIds.size() + "/" + sum);
                groupWarning.setTenantId(g.getTenantId());
                groupWarning.setGroupId(g.getId());
                groupWarning.setWarningTime(checkTime);
                GroupDTO groupDTO = new GroupDTO();
                groupDTO.setId(g.getId());
                groupDTO.setTenantId(g.getTenantId());
                String warningMsg = "";
                List<GroupDTO> groupDTOList = groupMapper.queryListByPage(groupDTO);
                if (!CollectionUtils.isEmpty(groupDTOList)) {
                    GroupDTO group = groupDTOList.get(0);
                    groupWarning
                            .setWarningRule(MessageFormat.format(WarningRule.GROUP_WARNING.getRule(), "null",
                                    String.valueOf(group.getName()),
                                    String.valueOf(group.getCompanyName()),
                                    String.valueOf(warningConfig.getGroup()), "null", "null", "null", "null", "null",
                                    "null"));
                    warningMsg = MessageFormat.format(WarningMsgTemplate.GROUP_WARNING.getRule(),
                            DateUtil.format(new Date(), com.easylinkin.linkappapi.common.utils.DateUtil.DATE_TIME_FORMAT_MINUTE),
                            String.valueOf(group.getName()),
                            String.valueOf(warningConfig.getGroup()));
                    groupWarning.setModifyTime(new Date());
                    groupWarning.setCreateTime(new Date());
                    groupWarningMapper.insert(groupWarning);
                    appSendMessageService.sendAppWarning(groupWarning.getId(), WaringType.GROUP_WARNING, warningMsg, g.getTenantId());
                }

            }
        });
    }

    private WarningConfig getWarningConfig(String tenantId, List<WarningConfig> configs) {
        //查询预警设置
        WarningConfig warningConfig;
        List<WarningConfig> list = configs.stream().filter(c -> tenantId.equals(c.getTenantId()))
                .collect(Collectors.toList());
        if (list.size() < 1) {
            List<WarningConfig> defaultVal = configs.stream()
                    .filter(c -> StringUtils.isBlank(c.getTenantId())).collect(Collectors.toList());
            warningConfig = defaultVal.get(0);
        } else {
            warningConfig = list.get(0);
        }
        return warningConfig;
    }

    public Date getDate(String time) {
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String s1 = format + " " + time;
        return DateUtil.parse(s1, "yyyy-MM-dd HH:mm");
    }

    /**
     * 人员出勤预警
     */
    private void userWaning(String tenantId, WarningConfig warningConfig) {
        List<UserWarning> addUserWarnings = new ArrayList<>();
        //查询预警时间内有出勤的
        List<UserProject> userProjects = userProjectMapper
                .selectByConfig(tenantId, warningConfig.getAbsent());
        List<UserProject> outProjects = userProjectMapper
                .selectByConfig(tenantId, warningConfig.getAutomaticExit());
        //统计退场的
        if (null != outProjects && outProjects.size() > 0) {
            Set<String> userIds = outProjects.stream().map(o -> o.getUserId())
                    .collect(Collectors.toSet());
            Date now = DateUtil.date();
            //20220908增加自动退场开关判断,20220915变更增加开关同时针对业务
            Integer automaticExitSwitch = warningConfig.getAutomaticExitSwitch();
            if (automaticExitSwitch != null && automaticExitSwitch.intValue() == 1) {
                userIds.forEach(u -> {
                    UserWarning userWarning = new UserWarning();
                    userWarning.setUserId(u);
                    userWarning.setTenantId(tenantId);
                    userWarning.setType(2);
                    EmpUserBaseDTO empUserBaseDTO = userProjectService.getByUserIdAndTenantIEmp(u, tenantId);
                    if (null != empUserBaseDTO) {
                        userWarning
                                .setWarningRule(MessageFormat.format(WarningRule.AUTOMATIC_EXIT_WARNING.getRule(),
                                        String.valueOf(empUserBaseDTO.getName()),
                                        String.valueOf(empUserBaseDTO.getUserProject().getGroupName()),
                                        String.valueOf(empUserBaseDTO.getUserProject().getCompanyName()),
                                        String.valueOf(warningConfig.getAutomaticExit()),
                                        String.valueOf(empUserBaseDTO.getUserProject().getWorkType()), "null", "null",
                                        "null", "null", "null"));
                        userWarning.setWarningMsg(MessageFormat.format(WarningMsgTemplate.AUTOMATIC_EXIT_WARNING.getRule(),
                                DateUtil.format(new Date(), com.easylinkin.linkappapi.common.utils.DateUtil.DATE_TIME_FORMAT_MINUTE),
                                String.valueOf(empUserBaseDTO.getUserProject().getGroupName()),
                                String.valueOf(empUserBaseDTO.getName()),
                                String.valueOf(warningConfig.getAutomaticExit())));
                        userWarning.setWarningTime(now);
                        userWarning.setCreateTime(now);
                        userWarning.setModifyTime(now);
                        //20220913增加直接设置告警处理状态，为系统自动处理
                        userWarning.setHandleUser("-1");
                        userWarning.setHandleTime(now);
                        userWarning.setStatus(1);
                        userWarning.setOperateType(0);
                        addUserWarnings.add(userWarning);

                        //20220913增加设置连续未出勤的预警为已处理
                        UpdateWrapper<UserWarning> uuw = new UpdateWrapper<>();
                        uuw.eq("user_id_", u);
                        uuw.eq("tenant_id_", tenantId);
                        uuw.eq("type_", 1);
                        uuw.eq("status_", 0);

                        uuw.set("handle_user_", -1);
                        uuw.set("handle_time_", now);
                        uuw.set("status_", 1);
                        uuw.set("operate_type", 0);
                        userWarningMapper.update(null, uuw);
                    }


                });
                //设置人员退场
                Set<String> ids = outProjects.stream().map(o -> o.getId()).collect(Collectors.toSet());
                UpdateWrapper<UserProject> updateWrapper = new UpdateWrapper<>();
                updateWrapper.in("id", ids)
                        .set("status_", 0)
                        .set("leave_time_", new Date())
                        .set("modify_time_", new Date());
                userProjectMapper.update(null, updateWrapper);
                //从闸机中删除
                userProjectService.delGateBatch(ids);
                //去掉退场的
                userProjects.removeIf(u -> userIds.contains(u.getUserId()));
            }
        }
        //处理连续未出勤的
        Integer absentSwitch = warningConfig.getAbsentSwitch();
        if (absentSwitch != null && absentSwitch.intValue() == 1) {
            if (userProjects.size() > 0) {
                //查询已有最新的预警信息
                Set<String> uIds = userProjects.stream().map(u -> u.getUserId())
                        .collect(Collectors.toSet());
                List<UserWarning> maxUserWarnings = userWarningMapper.findMaxByUserId(tenantId, uIds);
                List<String> removeUids = new ArrayList<>();
                if (maxUserWarnings.size() > 0) {
                    //去除跟现在时间间隔小于或等于预警设置值的数据
                    maxUserWarnings.forEach(m -> {
                        long day = DateUtil.betweenDay(m.getWarningTime(), new Date(), true);
                        if (day >= warningConfig.getAbsent()) {
                            //大于设置值要查询两个时间段有没有打卡记录
                            QueryWrapper<UserRecord> queryWrapper = new QueryWrapper<>();
                            queryWrapper.eq("tenant_id_", tenantId)
                                    .eq("user_id_", m.getUserId())
                                    .ge("record_time_", m.getWarningTime());
                            List<UserRecord> records = userRecordMapper.selectList(queryWrapper);
                            if (records.size() < 1) {
                                removeUids.add(m.getUserId());
                            }
                        }
                    });
                }
                //移除不需要记录的数据
                if (removeUids.size() > 0) {
                    userProjects.removeIf(u -> removeUids.contains(u.getUserId()));
                }

                int offSetDay = 0;
                Date now = DateUtil.date();
                if (warningConfig.getAbsent() != null) {
                    offSetDay = 0 - warningConfig.getAbsent();
                }
                Date startTime = DateUtil.beginOfDay(DateUtil.offsetDay(now, offSetDay));
                Date endTime = DateUtil.endOfDay(now);
                userProjects.forEach(u -> {
                    //20220909增加逻辑查询是否有已经处理/忽略的预警（近预警设置值时间内有处理、忽略的预警记录）
                    QueryWrapper<UserWarning> uw = new QueryWrapper<>();
                    uw.eq("tenant_id_", tenantId);
                    uw.eq("user_id_", u.getUserId());
                    uw.eq("type_", 1);
                    uw.ge("warning_time_", startTime);
                    uw.le("warning_time_", endTime);
                    uw.eq("status_", 1);
                    int dealNum = userWarningMapper.selectCount(uw);
                    //有处理或忽略就不生成
                    if (dealNum < 1) {
                        UserWarning userWarning = new UserWarning();
                        userWarning.setUserId(u.getUserId());
                        userWarning.setTenantId(tenantId);
                        userWarning.setType(1);
                        userWarning.setWarningTime(new Date());
                        EmpUserBaseDTO empUserBaseDTO = userProjectService
                                .getByUserIdAndTenantIEmp(u.getUserId(), tenantId);
                        if (null != empUserBaseDTO) {
                            long btDay = warningConfig.getAbsent();
                            //20220919增加查询最后一次打卡记录
                            QueryWrapper<UserRecord> urQw = new QueryWrapper<>();
                            urQw.eq("tenant_id_", tenantId);
                            urQw.eq("user_id_", u.getUserId());
                            urQw.ne("record_type_", 0);
                            urQw.gt("record_time_", DateUtil.offset(DateUtil.date(), DateField.YEAR, -1));
                            urQw.orderByDesc("record_time_");
                            urQw.last(" limit 1 ");
                            UserRecord lastDk = userRecordMapper.selectOne(urQw);
                            if (lastDk == null) {
                                //为空：表示重来没打卡
                                btDay = DateUtil.betweenDay(u.getJoinTime(), DateUtil.date(), true);
                            } else {
                                //最后一次打卡时间在进场时间前
                                if (lastDk.getRecordTime().before(u.getJoinTime())) {
                                    btDay = DateUtil.betweenDay(u.getJoinTime(), DateUtil.date(), true);
                                } else {
                                    btDay = DateUtil.betweenDay(lastDk.getRecordTime(), DateUtil.date(), true);
                                }
                            }

                            userWarning.setWarningRule(MessageFormat.format(WarningRule.ABSENT_WARNING.getRule(),
                                    String.valueOf(empUserBaseDTO.getName()),
                                    String.valueOf(empUserBaseDTO.getUserProject().getGroupName()),
                                    String.valueOf(empUserBaseDTO.getUserProject().getCompanyName()),
                                    String.valueOf(btDay),
                                    String.valueOf(empUserBaseDTO.getUserProject().getWorkType()), "null", "null",
                                    "null", "null", "null"));
                            userWarning.setWarningMsg(MessageFormat.format(WarningMsgTemplate.ABSENT_WARNING.getRule(),
                                    DateUtil.format(new Date(), com.easylinkin.linkappapi.common.utils.DateUtil.DATE_TIME_FORMAT_MINUTE),
                                    String.valueOf(empUserBaseDTO.getUserProject().getGroupName()),
                                    String.valueOf(empUserBaseDTO.getName()),
                                    String.valueOf(btDay)));
                            userWarning.setCreateTime(new Date());
                            userWarning.setModifyTime(new Date());
                            addUserWarnings.add(userWarning);
                        }

                    }
                });
            }
        }
        //插入数据
        addUserWarnings.forEach(u -> {
            userWarningMapper.insert(u);
            appSendMessageService.sendAppWarning(u.getId(), WaringType.USER_WARNINNG, u.getWarningMsg(), tenantId);
        });
    }

    /**
     * 年龄预警
     */
    private void ageWaning(String tenantId, WarningConfig warningConfig) {
        //查询人员
        QueryWrapper<UserProject> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("tenant_id_", tenantId)
                .eq("status_", 1);
        List<UserProject> userProjects = userProjectMapper.selectList(queryWrapper);
        List<UserProjectDTO> userProjectDTOS = BeanUtil.copyToList(userProjects, UserProjectDTO.class);
        userProjectDTOS.forEach(u -> u.setAge(DateUtil.age(u.getBirthday(), new Date())));
        //判断超龄人员
        List<UserProjectDTO> list = userProjectDTOS.stream().filter(u -> {
            //20220908增加年龄开关判断
            Boolean man = false;
            Boolean woman = false;
            Integer manAgeSwitch = warningConfig.getManAgeSwitch();
            if (manAgeSwitch != null && manAgeSwitch.intValue() == 1) {
                man = Integer.valueOf(1).equals(u.getGender()) && u.getAge() >= warningConfig.getManAge();
            }
            Integer womanAgeSwitch = warningConfig.getWomanAgeSwitch();
            if (womanAgeSwitch != null && womanAgeSwitch.intValue() == 1) {
                woman =
                        Integer.valueOf(2).equals(u.getGender()) && u.getAge() >= warningConfig.getWomanAge();
            }
            return man || woman;
        }).collect(Collectors.toList());
        //查询已预警
        QueryWrapper<AgeWarning> ageWrapper = new QueryWrapper<>();
        queryWrapper.eq("tenant_id_", tenantId);
        List<AgeWarning> ageWarnings = ageWarningMapper.selectList(ageWrapper);
        Set<String> userIds = ageWarnings.stream().map(a -> a.getUserId()).collect(Collectors.toSet());
        list.removeIf(l -> userIds.contains(l.getUserId()));
        //保存数据
        list.forEach(l -> {
            AgeWarning ageWarning = new AgeWarning();
            ageWarning.setUserId(l.getUserId());
            ageWarning.setTenantId(tenantId);
            ageWarning.setWarningTime(new Date());
            EmpUserBaseDTO empUserBaseDTO = userProjectService
                    .getByUserIdAndTenantIEmp(l.getUserId(), tenantId);
            String warningMsg = "";
            if (null != empUserBaseDTO) {
                ageWarning.setWarningRule(MessageFormat.format(WarningRule.AGE_WARNING.getRule(),
                        String.valueOf(empUserBaseDTO.getName()),
                        String.valueOf(empUserBaseDTO.getUserProject().getGroupName()),
                        String.valueOf(empUserBaseDTO.getUserProject().getCompanyName()),
                        String.valueOf(empUserBaseDTO.getUserProject().getWorkType()), "null", "null", "null",
                        "null", "null"));
                warningMsg = MessageFormat.format(WarningMsgTemplate.AGE_WARNING.getRule(),
                        DateUtil.format(new Date(), com.easylinkin.linkappapi.common.utils.DateUtil.DATE_TIME_FORMAT_MINUTE),
                        String.valueOf(empUserBaseDTO.getUserProject().getGroupName()),
                        String.valueOf(empUserBaseDTO.getName()));
                ageWarning.setModifyTime(new Date());
                ageWarning.setCreateTime(new Date());
                ageWarningMapper.insert(ageWarning);
                appSendMessageService.sendAppWarning(ageWarning.getId(), WaringType.AGE_WARNING, warningMsg, tenantId);
            }

        });
    }

    /**
     * 证书预警
     */
    private void certificateWarning(String tenantId, WarningConfig warningConfig) {
        //20220908增加证书预警开关判断
        Integer certificateSwitch = warningConfig.getCertificateSwitch();
        if (certificateSwitch == null || certificateSwitch.intValue() == 0) {
            return;
        }
        List<UserCertificate> userCertificates = userCertificateMapper.findByTenantId(tenantId);
        //已经预警的数据
        QueryWrapper<CertificateWarning> cWrapper = new QueryWrapper<>();
        cWrapper.eq("tenant_id_", tenantId);
        List<CertificateWarning> warnings = certificateWarningMapper.selectList(cWrapper);
        Set<String> cIds = warnings.stream().map(w -> w.getCertificateId())
                .collect(Collectors.toSet());
        //去掉没有到期时间的
        userCertificates.removeIf(u -> null == u.getStopTime());
        userCertificates.forEach(u -> {
            //判断是否过期
            long between = DateUtil.between(new Date(), u.getStopTime(), DateUnit.DAY, false);
            if (!cIds.contains(u.getId()) && between <= warningConfig.getCertificate()) {
                CertificateWarning certificateWarning = new CertificateWarning();
                certificateWarning.setCertificateId(u.getId());
                certificateWarning.setUserId(u.getUserId());
                certificateWarning.setTenantId(tenantId);
                certificateWarning.setLevel(u.getLevel());
                certificateWarning.setNo(u.getNo());
                certificateWarning.setName(u.getName());
                certificateWarning.setType(u.getType());
                certificateWarning.setResidueDay(between > 0 ? (int) between : 0);
                certificateWarning.setWarningTime(new Date());
                EmpUserBaseDTO empUserBaseDTO = userProjectService
                        .getByUserIdAndTenantIEmp(u.getUserId(), tenantId);
                String warningMsg = "";
                if (null != empUserBaseDTO) {
                    //TODO 需要增加判断是否有已处理的提醒？
                    String warningRuleStr = "";
                    if (between > 0) {
                        warningRuleStr = MessageFormat.format(
                                WarningRule.CERTIFICATE_WILL_EXPIRED_WARNING.getRule(),
                                String.valueOf(empUserBaseDTO.getName()),
                                String.valueOf(empUserBaseDTO.getUserProject().getGroupName()),
                                String.valueOf(empUserBaseDTO.getUserProject().getCompanyName()),
                                String.valueOf(between),
                                String.valueOf(empUserBaseDTO.getUserProject().getWorkType()),
                                String.valueOf(u.getName()), String.valueOf(u.getType()),
                                String.valueOf(u.getLevel()),
                                DateUtil.format(u.getStopTime(), DatePattern.NORM_DATE_PATTERN),
                                String.valueOf(u.getNo()));
                        warningMsg = MessageFormat.format(WarningMsgTemplate.CERTIFICATE_WILL_EXPIRED_WARNING.getRule(),
                                DateUtil.format(new Date(), com.easylinkin.linkappapi.common.utils.DateUtil.DATE_TIME_FORMAT_MINUTE),
                                String.valueOf(empUserBaseDTO.getUserProject().getGroupName()),
                                String.valueOf(empUserBaseDTO.getName()),
                                String.valueOf(between));
                    } else {
                        warningRuleStr = MessageFormat.format(WarningRule.CERTIFICATE_EXPIRED_WARNING.getRule(),
                                String.valueOf(empUserBaseDTO.getName()),
                                String.valueOf(empUserBaseDTO.getUserProject().getGroupName()),
                                String.valueOf(empUserBaseDTO.getUserProject().getCompanyName()),
                                String.valueOf(empUserBaseDTO.getUserProject().getWorkType()),
                                String.valueOf(u.getName()), String.valueOf(u.getType()),
                                String.valueOf(u.getLevel()),
                                DateUtil.format(u.getStopTime(), DatePattern.NORM_DATE_PATTERN),
                                String.valueOf(u.getNo()));
                        warningMsg = MessageFormat.format(WarningMsgTemplate.CERTIFICATE_EXPIRED_WARNING.getRule(),
                                DateUtil.format(new Date(), com.easylinkin.linkappapi.common.utils.DateUtil.DATE_TIME_FORMAT_MINUTE),
                                String.valueOf(empUserBaseDTO.getUserProject().getGroupName()),
                                String.valueOf(empUserBaseDTO.getName()));
                    }
                    certificateWarning.setWarningRule(warningRuleStr);
                    certificateWarning.setModifyTime(new Date());
                    certificateWarning.setCreateTime(new Date());
                    certificateWarningMapper.insert(certificateWarning);
                    appSendMessageService.sendAppWarning(certificateWarning.getId(), WaringType.AGE_WARNING, warningMsg, tenantId);
                }

            }
        });
    }
}
